<template>
    <div :class="[prefixCls]">
        <div :class="classes" @click="handleClick" @drop.prevent="onDrop" @paste="handlePaste"
            @dragover.prevent="dragOver = true" @dragleave.prevent="dragOver = false">
            <input ref="input" type="file" :class="[prefixCls + '-input']" @change="handleChange" :multiple="multiple"
                :webkitdirectory="webkitdirectory" :accept="accept">
            <slot></slot>
        </div>

        <slot name="tip"></slot>
        <upload-list v-if="showUploadList" :files="fileList" @on-file-remove="handleRemove"
            @on-file-preview="handlePreview"></upload-list>
    </div>
</template>
<script>
import UploadList from './upload-list.vue';
import ajax from './ajax';
import { oneOf } from '../../utils/assist';
import Emitter from '../../mixins/emitter';
import mixinsForm from '../../mixins/form';

const prefixCls = 'ivu-upload';

export default {
    name: 'Upload',
    mixins: [Emitter, mixinsForm],
    components: { UploadList },
    props: {
        action: {
            type: String,
            required: true
        },
        headers: {
            type: Object,
            default() {
                return {};
            }
        },
        multiple: {
            type: Boolean,
            default: false
        },
        data: {
            type: Object
        },
        name: {
            type: String,
            default: 'file'
        },
        withCredentials: {
            type: Boolean,
            default: false
        },
        showUploadList: {
            type: Boolean,
            default: true
        },
        type: {
            type: String,
            validator(value) {
                return oneOf(value, ['select', 'drag']);
            },
            default: 'select'
        },
        format: {
            type: Array,
            default() {
                return [];
            }
        },
        accept: {
            type: String
        },
        maxSize: {
            type: Number
        },
        beforeUpload: Function,
        onProgress: {
            type: Function,
            default() {
                return {};
            }
        },
        onSuccess: {
            type: Function,
            default() {
                return {};
            }
        },
        onError: {
            type: Function,
            default() {
                return {};
            }
        },
        onRemove: {
            type: Function,
            default() {
                return {};
            }
        },
        onPreview: {
            type: Function,
            default() {
                return {};
            }
        },
        onExceededSize: {
            type: Function,
            default() {
                return {};
            }
        },
        onFormatError: {
            type: Function,
            default() {
                return {};
            }
        },
        defaultFileList: {
            type: Array,
            default() {
                return [];
            }
        },
        paste: {
            type: Boolean,
            default: false
        },
        disabled: {
            type: Boolean,
            default: false
        },
        webkitdirectory: {
            type: Boolean,
            default: true
        }
    },
    data() {
        return {
            dealOverCount: 0,
            maxCountSameTime: 3,
            waitList: [],
            prefixCls: prefixCls,
            dragOver: false,
            fileList: [],
            tempIndex: 1
        };
    },
    computed: {
        classes() {
            return [
                `${prefixCls}`,
                {
                    [`${prefixCls}-select`]: this.type === 'select',
                    [`${prefixCls}-drag`]: this.type === 'drag',
                    [`${prefixCls}-dragOver`]: this.type === 'drag' && this.dragOver
                }
            ];
        },

    },
    methods: {
        handleClick() {
            if (this.itemDisabled) return;
            this.$refs.input.click();
        },
        //新增上传文件 外部调用
        addUploadFile(uploadFile) {
            this.uploadFiles([uploadFile]);
        },
        handleChange(e) {
            const files = e.target.files;
            if (!files) {
                return;
            }
            this.uploadFiles(files);
            this.$refs.input.value = null;
        },
        onDrop(e) {
            if (this.type != 'drag') {
                return
            }
            this.dragOver = false;
            if (this.itemDisabled) return;
            this.uploadFiles(e.dataTransfer.files);
        },
        handlePaste(e) {
            if (this.itemDisabled) return;
            if (this.paste) {
                this.uploadFiles(e.clipboardData.files);
            }
        },
        uploadFiles(files) {
            let startNow = false
            if (this.waitList.length < 1) {
                startNow = true
            }
            let postFiles = Array.prototype.slice.call(files);
            if (!this.multiple) postFiles = postFiles.slice(0, 1);
            if (postFiles.length === 0) return;
            postFiles.forEach(file => {
                this.waitList.push(file)
            });
            if (startNow) {
                this.startUpload()
            }
        },
        //按顺序一个一个上传
        startUpload() {
            this.dealOverCount = 0
            for (let i = 0; i < this.maxCountSameTime; i++) {
                if (this.waitList.length > 0) {
                    let upItem = this.waitList[0]
                    this.waitList.splice(0, 1)
                    console.log("this.upload(upItem);", upItem)
                    this.upload(upItem);
                }
            }
        },
        upload(file) {
            if (!this.beforeUpload) {
                return this.post(file);
            }

            const before = this.beforeUpload(file);
            if (before && before.then) {
                before.then(processedFile => {
                    if (Object.prototype.toString.call(processedFile) === '[object File]') {
                        this.post(processedFile);
                    } else {
                        this.post(file);
                    }
                }, () => {
                    console.log("拒绝了")
                    this.dealOverCount += 1
                    // this.$emit('cancel', file);
                });
            } else if (before !== false) {
                console.log("else else else ")
                this.post(file);
            } else {
                console.log("else else else ")
                // this.$emit('cancel', file);
            }
        },
        post(file) {
            // check format
            if (this.format.length) {
                const _file_format = file.name.split('.').pop().toLocaleLowerCase();
                const checked = this.format.some(item => item.toLocaleLowerCase() === _file_format);
                if (!checked) {
                    this.onFormatError(file, this.fileList);
                    return false;
                }
            }

            // check maxSize
            if (this.maxSize) {
                if (file.size > this.maxSize * 1024) {
                    this.onExceededSize(file, this.fileList);
                    return false;
                }
            }

            this.handleStart(file);
            let formData = new FormData();
            formData.append(this.name, file);
            // if(file.uploadUrl){
            //     console.log('使用file属性中的上传url')
            // }
            let xhr = ajax({
                headers: this.headers,
                withCredentials: this.withCredentials,
                file: file,
                data: this.data,
                filename: this.name,
                action: file.uploadUrl ? file.uploadUrl : this.action,
                onProgress: e => {
                    this.handleProgress(e, file);
                },
                onSuccess: res => {
                    this.handleSuccess(res, file);
                    this.dealOverCount += 1
                    console.log("onSuccess dealOverCount",this.dealOverCount)
                    if (this.dealOverCount >= this.maxCountSameTime || this.waitList.length < 1) {
                        this.startUpload()
                    }
                },
                onError: (err, response) => {
                    this.handleError(err, response, file);
                    this.dealOverCount += 1
                    console.log("onError dealOverCount",this.dealOverCount)
                    if (this.dealOverCount >= this.maxCountSameTime || this.waitList.length < 1) {
                        this.startUpload()
                    }
                }
            });
            //把xhr对象保存到列表里 后续可以调用abort暂停上传
            let fileIndex = this.getFileIndex(file)
            if (fileIndex != -1) {
                this.fileList[fileIndex].xhr = xhr
            }
        },
        handleStart(file) {
            file.uid = Date.now() + this.tempIndex++;
            const _file = {
                status: 'uploading',
                name: file.name,
                size: file.size,
                percentage: 0,
                uid: file.uid,
                showProgress: true
            };

            this.fileList.push(_file);
        },
        getFile(file) {
            const fileList = this.fileList;
            let target;
            fileList.every(item => {
                target = file.uid === item.uid ? item : null;
                return !target;
            });
            return target;
        },
        getFileIndex(file) {
            const fileList = this.fileList;
            for (let i in fileList) {
                if (fileList[i].uid == file.uid) {
                    return i
                }
            }
            return -1
        },
        handleProgress(e, file) {
            const _file = this.getFile(file);
            this.onProgress(e, _file, this.fileList);
            _file.percentage = e.percent || 0;
        },
        handleSuccess(res, file) {
            const _file = this.getFile(file);

            if (_file) {
                _file.status = 'finished';
                _file.response = res;

                this.onSuccess(res, _file, this.fileList, file);
                this.dispatch('FormItem', 'on-form-change', _file);

                setTimeout(() => {
                    _file.showProgress = false;
                }, 1000);
            }
        },
        handleError(err, response, file) {
            const _file = this.getFile(file);
            const fileList = this.fileList;

            _file.status = 'fail';

            fileList.splice(fileList.indexOf(_file), 1);

            this.onError(err, response, file);
        },
        handleRemove(file) {
            const fileList = this.fileList;
            fileList.splice(fileList.indexOf(file), 1);
            this.onRemove(file, fileList);
        },
        handlePreview(file) {
            if (file.status === 'finished') {
                this.onPreview(file);
            }
        },
        clearFiles() {
            this.fileList = [];
        }
    },
    watch: {
        defaultFileList: {
            immediate: true,
            handler(fileList) {
                this.fileList = fileList.map(item => {
                    item.status = 'finished';
                    item.percentage = 100;
                    item.uid = Date.now() + this.tempIndex++;
                    return item;
                });
            }
        }
    },
};
</script>
